package FileTool

import (
	"bufio"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"runtime"
	"strings"
)

func ChanReadLineFile(readFileFrom string) chan string {
	return ReadLineFile(readFileFrom)
}

func ReadLineFile(readFileFrom string) chan string {

	var chanLine = make(chan string)

	go func() {
		openFile, err := os.Open(readFileFrom)
		if err != nil {
			log.Fatal(err)
		}

		defer close(chanLine)
		defer openFile.Close()

		reader := bufio.NewReader(openFile)
		var long_bline_arr []string
		for {
			bline, isPrefix, err := reader.ReadLine()
			if err == io.EOF {
				break // 读取到文件结束才退出
			}

			// 读取到超长行，即单行超过4k字节，直接写入放入数组
			if isPrefix {
				long_bline_arr = append(long_bline_arr, string(bline))
				continue
			}
			//如果是超长字符串或短都放入数组了，所以需解析
			long_bline_arr = append(long_bline_arr, string(bline))
			//输出内容
			chanLine <- strings.Join(long_bline_arr, "")
			long_bline_arr = nil

		}
	}()

	return chanLine

}

func IsDir(path string) bool {
	s, err := os.Stat(path)
	if err != nil {

		return false
	}
	return s.IsDir()

}

// 判断所给路径文件/文件夹是否存在
func PathExists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		return true, nil
	}
	//isnotexist来判断，是不是不存在的错误
	if os.IsNotExist(err) { //如果返回的错误类型使用os.isNotExist()判断为true，说明文件或者文件夹不存在
		return false, nil
	}
	return false, err //如果有错误了，但是不是不存在的错误，所以把这个错误原封不动的返回
}

func IsFile(path string) bool {
	if IsDir(path) {
		return false
	} else {
		var rbool, _ = PathExists(path)
		return rbool
	}
}

func ReadWholeFile(readFileFrom string) string {
	data, err := ioutil.ReadFile(readFileFrom)
	if err != nil {
		fmt.Println("File reading error", err)
		return ""
	}
	return string(data)
}

//获取该文件路径下的所有文件
func GetDirAllSonFilePath(srcPath string) chan string {

	//检测目录正确性
	if srcInfo, err := os.Stat(srcPath); err != nil {
		log.Fatal(err)
	} else {
		if !srcInfo.IsDir() {
			e := errors.New(srcPath + "不是一个正确的目录！")
			log.Fatal(e)
		}
	}
	var chanPath = make(chan string)
	go func() {
		defer close(chanPath)
		err := filepath.Walk(srcPath, func(path string, f os.FileInfo, err error) error {
			if f == nil {
				return err
			}
			if !f.IsDir() {
				path := strings.Replace(path, "\\", "/", -1)
				chanPath <- path
			}
			return nil
		})
		if err != nil {
			log.Fatal(err)
		}
	}()

	return chanPath
}

func CopyEntireFile(from_path string, to_path string) (w int64, err error) {

	srcFile, err := os.Open(from_path)
	if err != nil {
		log.Fatal(err)
	}
	defer srcFile.Close()
	//分割path目录
	destSplitPathDirs := strings.Split(to_path, "/")

	//检测时候存在目录
	destSplitPath := ""
	for index, dir := range destSplitPathDirs {
		if index < len(destSplitPathDirs)-1 {
			destSplitPath = destSplitPath + dir + "/"
			b, _ := PathExists(destSplitPath)
			if b == false {
				//fmt.Println("创建目录:" + destSplitPath)
				//创建目录
				err := os.Mkdir(destSplitPath, os.ModePerm)
				if err != nil {
					log.Fatal(err)
				}
			}
		}
	}
	dstFile, err := os.Create(to_path)
	if err != nil {
		log.Fatal(err)
	}
	defer dstFile.Close()

	return io.Copy(dstFile, srcFile)
}

func CopyLineFile(from_path string, to_path string) {

}

//尾部插入字符串
func AppendToFile(file, str string) {
	f, err := os.OpenFile(file, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0660)
	if err != nil {
		fmt.Printf("Cannot open file %s!\n", file)
		return
	}
	defer f.Close()
	f.WriteString(str)
}

//创建file不存在的dir
func MkFileNotDir(path string) {
	path = strings.Replace(path, "\\", "/", -1)
	path = strings.Replace(path, "\\\\", "/", -1)
	destSplitPathDirs := strings.Split(path, "/")
	destSplitPath := ""
	for index, dir := range destSplitPathDirs {
		if index < len(destSplitPathDirs)-1 {
			destSplitPath = destSplitPath + dir + "/"
			b, _ := PathExists(destSplitPath)
			if b == false {
				//fmt.Println("创建目录:" + destSplitPath)
				//创建目录
				err := os.Mkdir(destSplitPath, os.ModePerm)
				if err != nil {
					log.Fatal(err)
				}
			}
		}
	}
}

//模糊查找相对路径下的文件
func GetAbsolutePathOfRelativePath(FileName string) string {
	workingDir, err := os.Getwd()
	if err != nil {
		fmt.Println("Failed to get current working directory:")
		panic(err)
	}
	exePath, err := os.Executable()
	if err != nil {
		fmt.Println("Failed to get exe directory:")
		panic(err)
	}

	// 获取可执行文件所在的文件夹路径
	exeDir := filepath.Dir(exePath)
	fileSeparator := "/"
	if runtime.GOOS == "windows" {
		fileSeparator = "\\"
	}

	if IsFile(exeDir + fileSeparator + FileName) {
		return exeDir + fileSeparator + FileName
	} else {
		return workingDir + fileSeparator + FileName
	}
}

//获取按行文件所有内容
func GetFileAllLineString(path string) (string, error) {
	openFile, err := os.Open(path)
	if err != nil {
		return "", err
	}

	defer openFile.Close()

	reader := bufio.NewReader(openFile)
	var long_bline_arr []string
	for {
		bline, isPrefix, err := reader.ReadLine()
		if err == io.EOF {
			break // 读取到文件结束才退出
		}

		// 读取到超长行，即单行超过4k字节，直接写入放入数组
		if isPrefix {
			long_bline_arr = append(long_bline_arr, string(bline))
			continue
		}
		//如果是超长字符串或短都放入数组了，所以需解析
		long_bline_arr = append(long_bline_arr, string(bline))
		//输出内容
	}
	return strings.Join(long_bline_arr, ""), nil
}

//获取文件大小
func getFileSize(filePath string) (int64, error) {
	f, err := os.Open(filePath)
	if err != nil {
		return 0, err
	}
	defer f.Close()

	// 移动文件指针到末尾
	info, err := f.Stat()
	if err != nil {
		return 0, err
	}

	// 返回文件大小
	return info.Size(), nil
}
